package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"
	D "websocket_apn/define"
	"websocket_apn/driver/xddq"
	"websocket_apn/log"
	"websocket_apn/proxy"

	"github.com/gorilla/websocket"
	"gopkg.in/ini.v1"
)

//
//// 用于模拟状态
//var status int
//
////export queryStatus
//func queryStatus() C.int {
//	return C.int(status) // 直接返回状态
//}
//
////eqxport gameStart
//func gameStart(username *C.char, password *C.char) {
//	// 模拟用户登录逻辑
//	if C.GoString(username) == "admin" && C.GoString(password) == "123456" {
//		status = 0                   // 正在登录
//		time.Sleep(10 * time.Second) // 模拟登录延迟
//		status = 2                   // 正在运行
//	} else {
//		status = 1 // 密码错误
//	}
//}

var WebSocketUrl = "wss://proxy-xddq.hdnd01.com/s3109673_ws"
var autoStarGame = 1

// 配置文件所在路径
var cfgPath = "config.ini"
var AllConfig Config
var cfgFile *ini.File

// Config 配置信息
type Config struct {
	Logger D.Logger `json:"logger"`
	Db     D.Db     `json:"db"`
	Game   D.Game   `json:"db"`
}

type ProxyServer struct {
	targetConn *websocket.Conn
}

var userInfo = D.UserInfo{
	Token:     "",
	WsAddress: WebSocketUrl,
}

func restartSelf() error {
	// 1. 获取当前进程的可执行文件路径和参数
	executable, err := os.Executable()
	if err != nil {
		return err
	}
	args := os.Args

	// 2. 启动新进程
	cmd := exec.Command(executable, args[1:]...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	cmd.Env = os.Environ()

	// 3. 启动新进程（不等待）
	err = cmd.Start()
	if err != nil {
		return err
	}

	// 4. 延迟一小段时间，确保新进程已启动
	time.Sleep(100 * time.Millisecond)

	// 5. 杀死当前进程
	os.Exit(0)
	return nil
}

// 参数识别
func Daemonize(args ...string) {
	sysType := runtime.GOOS
	//后台运行
	if sysType == "linux" {
		var arg []string
		if len(args) > 1 {
			arg = args[1:]
		}
		fmt.Println("run in backModed")
		cmd := exec.Command(args[0], arg...)
		cmd.Env = os.Environ()
		cmd.Start()
	} else if sysType == "windows" {

	}
}

// 初始化配置文件
func ConfigInit() Config {
	var err error
	// 检查文件是否存在
	if _, err := os.Stat(cfgPath); os.IsNotExist(err) {
		cfgFile, _ = ini.Load([]byte(`
[Log]
rollType = RollingFile
dir      = .
file     = log.txt
count    = 3
size     = 4
unit     = MB
level    = info
compress = 0

[Game]
Phone = 
PassWord = 
TokenTime =
Ptoken    = 
`))
	} else {
		cfgFile, err = ini.Load(cfgPath)
		if err != nil {
			log.Error(err)
		}
	}
	config := Config{}
	config.Db.Type = cfgFile.Section("DB").Key("type").String()
	config.Db.User = cfgFile.Section("DB").Key("user").String()
	config.Db.Pwd = cfgFile.Section("DB").Key("pwd").String()
	config.Db.IP = cfgFile.Section("DB").Key("ip").String()
	config.Db.Port = cfgFile.Section("DB").Key("port").String()
	config.Db.Database = cfgFile.Section("DB").Key("database").String()
	config.Db.Charset = cfgFile.Section("DB").Key("charset").String()

	Logger := D.Logger{
		RollType: cfgFile.Section("Log").Key("rollType").String(),
		Dir:      cfgFile.Section("Log").Key("dir").String(),
		File:     cfgFile.Section("Log").Key("file").String(),
		Count:    0,
		Size:     0,
		Unit:     cfgFile.Section("Log").Key("unit").String(),
		Level:    cfgFile.Section("Log").Key("level").String(),
		Compress: 0,
	}
	count, _ := cfgFile.Section("Log").Key("count").Int64()
	Logger.Count = int32(count)
	Logger.Size, _ = cfgFile.Section("Log").Key("size").Int64()
	Logger.Compress, _ = cfgFile.Section("Log").Key("compress").Int64()
	if Logger.RollType == "" {
		Logger.RollType = "RollingFile"
		Logger.Dir = "."
		Logger.File = "log.txt"
		Logger.Count = 1
		Logger.Size = 20
		Logger.Unit = "MB"
		Logger.Level = "info"
		Logger.Compress = 0
	}
	cfgLogger := Logger
	err = log.SetLogger(cfgLogger.RollType, cfgLogger.Dir, cfgLogger.File, cfgLogger.Count, cfgLogger.Size, cfgLogger.Unit, cfgLogger.Level,
		cfgLogger.Compress)
	if err != nil {
		log.Error("Init SetLogger err:", err.Error())
	}
	config.Logger = Logger

	config.Game.PlayerId, _ = cfgFile.Section("Game").Key("PlayerId").Int64()
	config.Game.Token = cfgFile.Section("Game").Key("Token").String()
	config.Game.LoginTime = cfgFile.Section("Game").Key("LoginTime").String()
	config.Game.Phone = cfgFile.Section("Game").Key("Phone").String()
	config.Game.PassWord = cfgFile.Section("Game").Key("PassWord").String()
	config.Game.Ptoken = cfgFile.Section("Game").Key("Ptoken").String()
	config.Game.TokenTime = cfgFile.Section("Game").Key("TokenTime").String()
	return config
}

// 保存配置文件
func ConfigSave(section, key, value string) {
	if cfgFile == nil {
		return
	}
	cfgFile.Section(section).Key(key).SetValue(value)
	cfgFile.SaveTo(cfgPath)
}
func checkIsRun() {
	// 获取当前程序的路径
	executable, err := os.Executable()
	if err != nil {
		fmt.Println("Error getting executable:", err)
		return
	}

	// 获取程序名
	programName := filepath.Base(executable)

	fmt.Println("Program Name:", programName)

	// 使用 pgrep 命令查找进程
	out, err := exec.Command("pgrep", programName).Output()
	if err != nil {
		fmt.Println("Error finding process:", err)
		return
	}

	// 转换输出为 PID
	pidStr := strings.TrimSpace(string(out))

	if pidStr == "" {
		fmt.Println("No process found with the name:", programName)
		return
	}

	// 获取当前进程的 PID
	currentPID := os.Getpid()

	// `pgrep` 可能返回多个 PID，用换行分隔
	pids := strings.Split(pidStr, "\n")

	for _, pidStr := range pids {
		pid, err := strconv.Atoi(strings.TrimSpace(pidStr))
		if err != nil {
			fmt.Println("Error converting PID:", err)
			continue
		}

		// 跳过当前进程的 PID
		if pid == currentPID {
			fmt.Printf("Skipping current process with PID %d.\n", pid)
			continue
		}

		// 如果找到其他进程，杀死它
		if pid > 0 {
			fmt.Printf("Killing process %d...\n", pid)

			// 使用 kill 命令来终止进程
			err = exec.Command("kill", "-9", strconv.Itoa(pid)).Run()
			if err != nil {
				fmt.Println("Error killing process:", err)
			} else {
				fmt.Printf("Process %d killed successfully.\n", pid)
			}
		}
	}
}

func main() {
	/*
		-d 后台运行
		-u 3109700
	*/
	args := os.Args
	daemon := false
	userAccount := 0
	if runtime.GOOS == "linux" {
		checkIsRun()
		log.Infof("%+v", args)
		for k, v := range args {
			if v == "-d" {
				daemon = true
				args[k] = ""
			} else if v == "restart" {
				daemon = true
				args[k] = ""
			} else if v == "-u" {
				userNum, _ := strconv.ParseInt(args[k+1], 10, 64)
				userAccount = int(userNum)
			}
		}
		if daemon {
			Daemonize(args...)
			return
		}
	}
	AllConfig = ConfigInit()
	loginByPhone := false
	if loginByPhone && (len(AllConfig.Game.Phone) == 0 || len(AllConfig.Game.PassWord) == 0) {
		AllConfig.Game.Phone = ""
		AllConfig.Game.PassWord = ""
		for {
			if len(AllConfig.Game.Phone) == 0 || strings.Contains(AllConfig.Game.Phone, "@xgd.com") == false {
				fmt.Printf("请输入游戏绑定的手机号\n")
				_, err := fmt.Scan(&AllConfig.Game.Phone)
				if err != nil || !regexp.MustCompile(`^1[3-9]\d{9}$`).MatchString(AllConfig.Game.Phone) {
					fmt.Printf("你输入的手机号[%s]不符合规范，请重新输入\n", AllConfig.Game.Phone)
					AllConfig.Game.Phone = ""
					continue
				}
				fmt.Printf("你的账号:[%s]\n", AllConfig.Game.Phone)
				break
			} else {
				fmt.Printf("你的账号:[%s]\n", AllConfig.Game.Phone)
				break
			}
		}
		for {
			if len(AllConfig.Game.PassWord) == 0 || strings.Contains(AllConfig.Game.PassWord, "@xgd.com") == false {
				fmt.Printf("请输入登录密码\n")
				_, err := fmt.Scan(&AllConfig.Game.PassWord)
				if err != nil {
					fmt.Printf("输入有误，请重新输入\n")
					AllConfig.Game.PassWord = ""
					continue
				}
				break
			} else {
				break
			}
		}
	}
	CurrentTime := time.Now()
	if AllConfig.Game.PlayerId > 0 && len(AllConfig.Game.Token) > 0 && len(AllConfig.Game.LoginTime) > 0 {
		gTokenTime, _ := time.Parse("2006-01-02 15:04:05", AllConfig.Game.LoginTime)
		log.Warnf("使用缓存Token登录, PlayerId:%d Token:%s LoginTime:%s", AllConfig.Game.PlayerId, AllConfig.Game.Token, AllConfig.Game.LoginTime)
		//Token还有效直接启动
		if gTokenTime.AddDate(0, 1, 0).After(CurrentTime) {
			if err := xddq.StartGame(D.UserInfo{PlayerId: AllConfig.Game.PlayerId, Token: AllConfig.Game.Token}); err == D.ErrorTimeOut {
				log.Warnf("清除失效的缓存Token; PlayerId:%d Token:%s LoginTime:%s", AllConfig.Game.PlayerId, AllConfig.Game.Token, AllConfig.Game.LoginTime)
				ConfigSave("Game", "Token", "")
			}
		} else {
			log.Warnf("清除已过期的缓存Token; PlayerId:%d Token:%s LoginTime:%s", AllConfig.Game.PlayerId, AllConfig.Game.Token, AllConfig.Game.LoginTime)
			ConfigSave("Game", "Token", "")
		}
	}
	loginInfo := &xddq.LoginInfo{
		Puid:       AllConfig.Game.Phone,    //手机号
		Pwd:        AllConfig.Game.PassWord, //密码
		Ptoken:     AllConfig.Game.Ptoken,
		Account:    userAccount,                                                                                                                                                                                                                                                                                           //
		DeviceInfo: "IC=1|DF=android|OS=7.1.2|AT=1722955635|DC=d44f8b56b615c7933ebc4f26e3208dd7|PM=V2304A|PMN=|BW=|AC=3973ec82-8b5c-4c60-ab04-837594758d3d|RL=1440*3008|PN=com.global.xddq.t3p|PV=2.1.00|SDKV=3.17.1|IDFA=|UEADID=e797ee1e92c52c3b|ADID=6ebd7659f2df727dbb17a522d19b5eff|IMEI=|OAID=|CHANNEL_ID=36306328", //未加密的设备信息
	}

	tokenTime, _ := time.Parse("2006-01-02 15:04:05", AllConfig.Game.TokenTime)
	if len(AllConfig.Game.TokenTime) == 0 || tokenTime.Before(CurrentTime) {
		pwdLoginRsp := xddq.LoginByPwd(loginInfo)
		if pwdLoginRsp == nil {
			log.Errorf("登录账号失败")
			//return
		} else {
			ConfigSave("Game", "Phone", loginInfo.Puid)
			ConfigSave("Game", "PassWord", loginInfo.Pwd)
			ConfigSave("Game", "Ptoken", loginInfo.Ptoken)
			ConfigSave("Game", "TokenTime", CurrentTime.AddDate(0, 0, 30).Format("2006-01-02 15:04:05"))
		}
	}
	err := xddq.LoginByPhoneAndStartGame(loginInfo)
	if err != nil {
		log.Errorf("登录账号失败: %s", err.Error())
		if strings.Contains(err.Error(), "密码可能不正确") {
			ConfigSave("Game", "Ptoken", "")
		}
		if runtime.GOOS == "linux" {
			os.Exit(0)
		}
		userInfo := proxy.StartTransparentProxy()
		if userInfo.PlayerId > 0 {
			timeNow := time.Now().Format("2006-01-02 15:04:05")
			ConfigSave("Game", "PlayerId", fmt.Sprintf("%d", userInfo.PlayerId))
			ConfigSave("Game", "Token", userInfo.Token)
			ConfigSave("Game", "LoginTime", timeNow)
			log.Warnf("检查到游戏信息: 玩家名[%s] ID[%d], 是否开始为你自动挂机?\n如需挂机请在关闭电脑端游戏后按任意键继续。。。", userInfo.NickName, userInfo.PlayerId)
			fmt.Scanln()
			restartSelf()
		}
	} else {
		log.Infof("登录成功, 区服:%s 玩家ID:%d 玩家名称:%s", loginInfo.ServerList.ServerName, userInfo.PlayerId, userInfo.NickName)
		ConfigSave("Game", "PlayerId", fmt.Sprintf("%d", loginInfo.UserInfo.PlayerId))
		ConfigSave("Game", "Token", loginInfo.UserInfo.Token)
		ConfigSave("Game", "LoginTime", CurrentTime.Format("2006-01-02 15:04:05"))
		xddq.GiftSign(loginInfo.Ptoken)
		xddq.StartGame(loginInfo.UserInfo)
	}

	log.Warnf("结束运行，请按任意键继续。。。")
	time.Sleep(2 * time.Second)
}
